home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Format CD 49
/
Amiga Format CD49 (2000-01-17)(Future Publishing)(GB)(Track 1 of 3)[!][issue 2000-02].iso
/
-serious-
/
graphics
/
gnuplot
/
gnuplot-3.7.1src
/
gnuplot-3.7.1
/
matrix.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-11-29
|
7KB
|
269 lines
#ifndef lint only calculate Sid = "$Id: matrix.c,v 1.12 1998/11/19 10:40:31 lhecking Exp $";
#endif
/*
* Matrix algebra, part of
*
* Nonlinear least squares fit according to the
* Marquardt-Levenberg-algorithm
*
* added as Patch to Gnuplot (v3.2 and higher)
* by Carsten Grammes
* Experimental Physics, University of Saarbruecken, Germany
*
* Internet address: cagr@rz.uni-sb.de
*
* Copyright of this module: Carsten Grammes, 1993
*
* Permission to use, copy, and distribute this software and its
* documentation for any purpose with or without fee is hereby granted,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation.
*
* This software is provided "as is" without express or implied warranty.
*/
#include "fit.h"
#include "matrix.h"
#include "stdfn.h"
#include "alloc.h"
/*****************************************************************/
#define Swap(a,b) {double temp = (a); (a) = (b); (b) = temp;}
#define WINZIG 1e-30
/*****************************************************************
internal prototypes
*****************************************************************/
static GP_INLINE int fsign __PROTO((double x));
/*****************************************************************
first straightforward vector and matrix allocation functions
*****************************************************************/
double *vec (n)
int n;
{
/* allocates a double vector with n elements */
double *dp;
if( n < 1 )
return (double *) NULL;
dp = (double *) gp_alloc ( n * sizeof(double), "vec");
return dp;
}
double **matr (rows, cols)
int rows;
int cols;
{
/* allocates a double matrix */
register int i;
register double **m;
if ( rows < 1 || cols < 1 )
return NULL;
m = (double **) gp_alloc ( rows * sizeof(double *) , "matrix row pointers");
m[0] = (double *) gp_alloc ( rows * cols * sizeof(double), "matrix elements");
for ( i = 1; i<rows ; i++ )
m[i] = m[i-1] + cols;
return m;
}
void free_matr (m)
double **m;
{
free (m[0]);
free (m);
}
double *redim_vec (v, n)
double **v;
int n;
{
if ( n < 1 )
*v = NULL;
else
*v = (double *) gp_realloc (*v, n * sizeof(double), "vec");
return *v;
}
void redim_ivec (v, n)
int **v;
int n;
{
if ( n < 1 ) {
*v = NULL;
return;
}
*v = (int *) gp_realloc (*v, n * sizeof(int), "ivec");
}
/* HBB: TODO: is there a better value for 'epsilon'? how to specify
* 'inline'? is 'fsign' really not available elsewhere? use
* row-oriented version (p. 309) instead?
*/
static GP_INLINE int fsign(x)
double x;
{
return( x>0 ? 1 : (x < 0) ? -1 : 0) ;
}
/*****************************************************************
Solve least squares Problem C*x+d = r, |r| = min!, by Given rotations
(QR-decomposition). Direct implementation of the algorithm
presented in H.R.Schwarz: Numerische Mathematik, 'equation'
number (7.33)
If 'd == NULL', d is not accesed: the routine just computes the QR
decomposition of C and exits.
If 'want_r == 0', r is not rotated back (\hat{r} is returned
instead).
*****************************************************************/
void Givens (C, d, x, r, N, n, want_r)
double **C;
double *d;
double *x;
double *r;
int N;
int n;
int want_r;
{
int i, j, k;
double w, gamma, sigma, rho, temp;
double epsilon = DBL_EPSILON; /* FIXME (?)*/
/*
* First, construct QR decomposition of C, by 'rotating away'
* all elements of C below the diagonal. The rotations are
* stored in place as Givens coefficients rho.
* Vector d is also rotated in this same turn, if it exists
*/
for (j = 0; j<n; j++)
for (i = j+1; i<N; i++)
if (C[i][j]) {
if (fabs(C[j][j])<epsilon*fabs(C[i][j])) { /* find the rotation parameters */
w = -C[i][j];
gamma = 0;
sigma = 1;
rho = 1;
} else {
w = fsign(C[j][j])*sqrt(C[j][j]*C[j][j] + C[i][j]*C[i][j]);
if (w == 0)
Eex3 ( "w = 0 in Givens(); Cjj = %g, Cij = %g", C[j][j], C[i][j]);
gamma = C[j][j]/w;
sigma = -C[i][j]/w;
rho = (fabs(sigma)<gamma) ? sigma : fsign(sigma)/gamma;
}
C[j][j] = w;
C[i][j] = rho; /* store rho in place, for later use */
for (k = j+1; k<n; k++) { /* rotation on index pair (i,j) */
temp = gamma*C[j][k] - sigma*C[i][k];
C[i][k] = sigma*C[j][k] + gamma*C[i][k];
C[j][k] = temp;
}
if (d) { /* if no d vector given, don't use it */
temp = gamma*d[j] - sigma*d[i]; /* rotate d */
d[i] = sigma*d[j] + gamma*d[i];
d[j] = temp;
}
}
if (!d) /* stop here if no d was specified */
return;
for (i = n-1; i >= 0; i--) { /* solve R*x+d = 0, by backsubstitution */
double s = d[i];
r[i] = 0; /* ... and also set r[i] = 0 for i<n */
for (k = i+1; k<n; k++)
s += C[i][k]*x[k];
if (C[i][i] == 0)
Eex ( "Singular matrix in Givens()");
x[i] = - s / C[i][i];
}
for (i = n; i < N; i++)
r[i] = d[i]; /* set the other r[i] to d[i] */
if (!want_r) /* if r isn't needed, stop here */
return;
/* rotate back the r vector */
for (j = n-1; j >= 0; j--)
for (i = N-1; i >= 0; i--) {
if ((rho = C[i][j]) == 1) { /* reconstruct gamma, sigma from stored rho */
gamma = 0;
sigma = 1;
} else if (fabs(rho)<1) {
sigma = rho;
gamma = sqrt(1-sigma*sigma);
} else {
gamma = 1/fabs(rho);
sigma = fsign(rho)*sqrt(1-gamma*gamma);
}
temp = gamma*r[j] + sigma*r[i]; /* rotate back indices (i,j) */
r[i] = -sigma*r[j] + gamma*r[i];
r[j] = temp;
}
}
/* Given a triangular Matrix R, compute (R^T * R)^(-1), by forward
* then back substitution
*
* R, I are n x n Matrices, I is for the result. Both must already be
* allocated.
*
* Will only calculate the lower triangle of I, as it is symmetric
*/
void Invert_RtR ( R, I, n)
double **R;
double **I;
int n;
{
int i, j, k;
/* fill in the I matrix, and check R for regularity : */
for (i = 0; i<n; i++) {
for (j = 0; j<i; j++) /* upper triangle isn't needed */
I[i][j] = 0;
I[i][i] = 1;
if (! R[i][i])
Eex ("Singular matrix in Invert_RtR")
}
/* Forward substitution: Solve R^T * B = I, store B in place of I */
for (k = 0; k<n; k++)
for (i = k; i<n; i++) { /* upper half needn't be computed */
double s = I[i][k];
for (j = k; j<i; j++) /* for j<k, I[j][k] always stays zero! */
s -= R[j][i] * I[j][k];
I[i][k] = s / R[i][i];
}
/* Backward substitution: Solve R * A = B, store A in place of B */
for (k = 0; k<n; k++)
for (i = n-1; i >= k; i--) { /* don't compute upper triangle of A */
double s = I[i][k];
for (j = i+1; j<n; j++)
s -= R[i][j] * I[j][k];
I[i][k] = s / R[i][i];
}
}